//
//  Utils.mm
//  OpenGLGame
//
//  Created by Nguyen Cong Huy on 3/3/13.
//  Copyright (c) 2013 UIT. All rights reserved.
//

#include "Utils.h"
#import "OCImage.h"
#import "mach/mach.h"

@implementation Utils


+ (UIImage*)scaledToSizeWithRGBA:(CGSize)toSize image:(UIImage*)image;
{
    UIImage *scaledImg = nil;
    float scaleRatio = GetScaleForProportionalResize(image.size, toSize, true, false );
    CGImageRef cgImage = CreateCGImageFromUIImageScaledWithRGBA(image, scaleRatio );
    if( cgImage ){
        scaledImg = [UIImage imageWithCGImage:cgImage];
        CGImageRelease( cgImage );
    } else {
        return nil;
    }
    return scaledImg;
}

+ (UIColor*)averageColorOfImage:(UIImage*)image rect:(CGRect)rect{
    float avgRed = 0, avgGreen = 0, avgBlue = 0;
    
    CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
    const UInt8* data = CFDataGetBytePtr(pixelData);
    
    int width = rect.size.width + rect.origin.x;
    for (int i = rect.origin.x; i < width; i++) {
        int height = rect.size.height + rect.origin.y;
        for (int j = rect.origin.y; j < height; j++) {
            int pixelInfo = ((image.size.width  * j) + i ) * 4;
            avgRed +=  data[pixelInfo]/255.0;
            avgGreen +=  data[pixelInfo + 1]/255.0;
            avgBlue +=  data[pixelInfo + 2]/255.0;
        }
    }
    
    CFRelease(pixelData);
    avgRed /= rect.size.width*rect.size.height;
    avgGreen /= rect.size.width*rect.size.height;
    avgBlue /= rect.size.width*rect.size.height;
    
    return [UIColor colorWithRed:avgRed green:avgGreen blue:avgBlue alpha:1.0];
}

+ (bool)is568Height{
    if([UIScreen mainScreen].bounds.size.height == 568){
        return true;
    }
    return false;
}

@end


float GetScaleForProportionalResize( CGSize theSize, CGSize intoSize, bool onlyScaleDown, bool maximize )
{
    float
    sx = theSize.width;
    float
    sy = theSize.height;
    float
    dx = intoSize.width;
    float
    dy = intoSize.height;
    float
    scale = 1;
    if( sx != 0 && sy != 0 )
    {
        dx
        = dx / sx;
        dy
        = dy / sy;
        // if maximize is true, take LARGER of the scales, else smaller
        if( maximize )
            scale = (dx > dy)
            ? dx : dy;
        else
            scale = (dx < dy)
            ? dx : dy;
        if( scale > 1 && onlyScaleDown )
            scale
            = 1;
    }
    else
    {
        scale
        = 0;
    }
    return scale;
}

CGImageRef CreateCGImageFromUIImageScaledWithRGBA( UIImage* image, float scaleFactor )
{
    CGImageRef newImage = NULL;
    CGContextRef bmContext = NULL;
    BOOL mustTransform  = YES;
    CGAffineTransform transform = CGAffineTransformIdentity;
    UIImageOrientation orientation = image.imageOrientation;
    CGImageRef srcCGImage = CGImageRetain( image.CGImage );
    size_t width = CGImageGetWidth(srcCGImage) * scaleFactor;
    size_t height = CGImageGetHeight(srcCGImage) * scaleFactor;
    // These Orientations are rotated 0 or 180 degrees, so they retain the width/height of the image
    if( (orientation == UIImageOrientationUp) || (orientation == UIImageOrientationDown) || (orientation == UIImageOrientationUpMirrored) || (orientation == UIImageOrientationDownMirrored)  )
    {
        bmContext = CGBitmapContextCreate( NULL, width, height, 8, 4*width, CGImageGetColorSpace(srcCGImage),
                                          kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
        if (!bmContext) {
            bmContext
            = CGBitmapContextCreate( NULL, width, height, 8, 4*width, CGImageGetColorSpace(srcCGImage),
                                    CGImageGetBitmapInfo(srcCGImage) );
        }
    }
    else
        // The other Orientations are rotated ±90 degrees, so they swap width & height.
    {
        bmContext = CGBitmapContextCreate( NULL, height, width, 8, 4*height, CGImageGetColorSpace(srcCGImage),
                                          kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
        if (!bmContext) {
            bmContext
            = CGBitmapContextCreate( NULL, height, width, 8, 4*height, CGImageGetColorSpace(srcCGImage),
                                    CGImageGetBitmapInfo(srcCGImage) );
        }
    }
    if (!bmContext) {
        CGImageRelease( srcCGImage );
        return nil;
    }
    
    //CGContextSetInterpolationQuality( bmContext, kCGInterpolationLow );
    CGContextSetBlendMode( bmContext, kCGBlendModeCopy );
    // we just want to copy the data
    switch(orientation)
    {
        case UIImageOrientationDown:
            // 0th row is at the bottom, and 0th column is on the right - Rotate 180 degrees
            transform = CGAffineTransformMake(-1.0, 0.0, 0.0, -1.0, width, height);
            break;
        case UIImageOrientationLeft:
            // 0th row is on the left, and 0th column is the bottom - Rotate -90 degrees
            transform = CGAffineTransformMake(0.0, 1.0, -1.0, 0.0, height, 0.0);
            break;
        case UIImageOrientationRight:
            // 0th row is on the right, and 0th column is the top - Rotate 90 degrees
            transform = CGAffineTransformMake(0.0, -1.0, 1.0, 0.0, 0.0, width);
            break;
        case UIImageOrientationUpMirrored:
            // 0th row is at the top, and 0th column is on the right - Flip Horizontal
            transform = CGAffineTransformMake(-1.0, 0.0, 0.0, 1.0, width, 0.0);
            break;
        case UIImageOrientationDownMirrored:
            // 0th row is at the bottom, and 0th column is on the left - Flip Vertical
            transform = CGAffineTransformMake(1.0, 0.0, 0, -1.0, 0.0, height);
            break;
        case UIImageOrientationLeftMirrored:
            // 0th row is on the left, and 0th column is the top - Rotate -90 degrees and Flip Vertical
            transform = CGAffineTransformMake(0.0, -1.0, -1.0, 0.0, height, width);
            break;
        case UIImageOrientationRightMirrored:
            // 0th row is on the right, and 0th column is the bottom - Rotate 90 degrees and Flip Vertical
            transform = CGAffineTransformMake(0.0, 1.0, 1.0, 0.0, 0.0, 0.0);
            break;
        default:
            mustTransform = NO;
            break;
    }
    if( mustTransform )
        CGContextConcatCTM( bmContext, transform );
    CGContextDrawImage( bmContext, CGRectMake(0.0, 0.0, width, height), srcCGImage );
    CGImageRelease( srcCGImage );
    newImage = CGBitmapContextCreateImage( bmContext );
    CFRelease( bmContext );
    return newImage;
}

short swapEndianness2Bytes(short s){
    //return s>>8 | s<<8;
    short result;
    unsigned char* cS = (unsigned char*)&s;
    unsigned char* cResult = (unsigned char*)&result;
    cResult[0] = cS[1];
    cResult[1] = cS[0];
    return result;
}

vm_size_t usedMemory(void) {
    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
    return (kerr == KERN_SUCCESS) ? info.resident_size : 0; // size in bytes
}

vm_size_t freeMemory(void) {
    mach_port_t host_port = mach_host_self();
    mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    vm_size_t pagesize;
    vm_statistics_data_t vm_stat;
    
    host_page_size(host_port, &pagesize);
    (void) host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
    return vm_stat.free_count * pagesize;
}

void logMemUsage(void) {
    // compute memory usage and log if different by >= 100k
    static long prevMemUsage = 0;
    long curMemUsage = usedMemory();
    long memUsageDiff = curMemUsage - prevMemUsage;
    
    if (memUsageDiff > 100000 || memUsageDiff < -100000) {
        prevMemUsage = curMemUsage;
        NSLog(@"Memory used %7.1f (%+5.0f), free %7.1f kb", curMemUsage/1000.0f, memUsageDiff/1000.0f, freeMemory()/1000.0f);
    }
}